/*
 *    Copyright 2009-2023 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.ryan;

import com.google.common.base.CaseFormat;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Date;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.Tool;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.jdbc.AbstractSQL;
import org.apache.ibatis.ryan.annotations.FieldColumn;
import org.joda.time.DateTime;

public class Tools {
  public static String eq = "%s = #{%s.%s}";
  public static String notEq = "%s != #{%s.%s}";
  public static String like = "%s LIKE CONCAT('%%',#{%s.%s},'%%')";
  public static String low = "%s < #{%s.%s}";
  public static String lowEq = "%s <= #{%s.%s}";
  public static String big = "%s > #{%s.%s}";
  public static String bigEq = "%s >= #{%s.%s}";

  /**
   * 构建变量名称
   *
   * @param prop
   *
   * @return
   */
  public static String buildVarName(String prop) {
    String lowUnder = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, prop);
    return lowUnder.replaceAll("\\.", "_");
  }

  /**
   * 构建变量值
   *
   * @param prop
   * @param params
   * @param pre
   * @param value
   *
   * @return
   */
  public static String buildVar(String prop, Map<String, Object> params, String pre, Object value) {
    String lowUnder = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, prop);
    String varName = lowUnder.replaceAll("\\.", "_");
    if (params.containsKey(varName)) {
      varName = varName + "_" + (new Random(Instant.now().toEpochMilli())).nextInt();
    }

    if (pre != null) {
      String key = pre + "_" + varName;
      params.put(key, formatIfDate(value));
      return key;
    } else {
      params.put(varName, formatIfDate(value));
      return varName;
    }
  }

  /**
   * 格式化日期时间 yyyy-MM-dd HH:mm:ss
   *
   * @param value
   *
   * @return
   */
  public static Object formatIfDate(Object value) {
    if (value == null) {
      return value;
    } else {
      if (value.getClass().isAssignableFrom(Date.class)) {
        value = (new DateTime(value)).toString("yyyy-MM-dd HH:mm:ss");
      }

      return value;
    }
  }

  /**
   * 下划线分割
   *
   * @param prop
   *
   * @return
   */
  public static String toUnderLine(String prop) {
    String lowUnder = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, prop);
    return lowUnder;
  }

  /**
   * 驼峰分割
   *
   * @param prop
   *
   * @return
   */
  public static String toCamelCase(String prop) {
    prop = toUnderLine(prop);
    String lowUnder = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, prop);
    return lowUnder;
  }

  /**
   * 属性名称转列名
   *
   * @param prop
   *
   * @return
   */
  public static String propToCol(String prop) {
    String lowUnder = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, prop);
    return lowUnder.replaceAll("\\.", "_");
  }

  /**
   * java 类型转表名称
   *
   * @param tableType
   *
   * @return
   */
  public static String tableName(Class<?> tableType) {
    return toUnderLine(tableType.getSimpleName()).replaceAll("_model|_do", "");
  }

  public static List<Field> getInstanceFields(Class<?> cls) {
    List<Field> fields = new ArrayList<>();
    Field[] declaredFields = cls.getDeclaredFields();
    Field[] var3 = declaredFields;
    int var4 = declaredFields.length;

    for (int var5 = 0; var5 < var4; ++var5) {
      Field f = var3[var5];
      String modifier = Modifier.toString(f.getModifiers());
      if (!modifier.contains("static") && !f.getType().equals(List.class)) {
        fields.add(f);
      }
    }

    return fields;
  }

  /**
   * 获取对象属性值
   *
   * @param <E>
   * @param bean
   * @param field
   *
   * @return
   */
  public static <E> E getFieldValue(Object bean, Field field) {
    E value = null;

    try {
      field.setAccessible(true);
      value = (E) field.get(bean);
    } catch (IllegalAccessException var4) {
      LogFactory.getLog(Tool.class).error(var4.getMessage(), var4);
    }

    return value;
  }

  /**
   * @param type
   * @param table
   * @param higGroupId
   *
   * @return
   */
  public static String[] fieldToCols(Class<?> type, String table, int higGroupId) {
    List<String> list = new ArrayList<>();
    List<Field> fields = getInstanceFields(type);
    Iterator<Field> var5 = fields.iterator();

    while (true) {
      while (var5.hasNext()) {
        Field field = (Field) var5.next();
        FieldColumn column = (FieldColumn) field.getAnnotation(FieldColumn.class);
        if (higGroupId == -1 && column == null) {
          list.add(toUnderLine(table + "." + field.getName()));
        } else if (null != column) {
          int[] groupIds = column.value();
          if (containGroup(higGroupId, groupIds)) {
            String aliAsName = parseAlias(column.column(), higGroupId);
            if (StringUtils.isNotBlank(aliAsName)) {
              String col = String.format("%s.%s %s", table, field.getName(), aliAsName);
              list.add(toUnderLine(col));
            } else {
              list.add(toUnderLine(table + "." + field.getName()));
            }
          }
        }
      }

      return (String[]) list.toArray(new String[0]);
    }
  }

  /**
   * 根据分组确认列所在表的别名
   *
   * @param aliAsName
   * @param groupId
   *
   * @return
   */
  private static String parseAlias(String aliAsName, int groupId) {
    if (groupId == 1) {
      Matcher matcher = Pattern.compile("((^1)|(,1)):(\\w+)").matcher(aliAsName);
      if (matcher.find()) {
        return matcher.group(4);
      }
    }

    Pattern pattern = Pattern.compile(String.format("%s:(\\w+)", groupId));
    Matcher matcher = pattern.matcher(aliAsName);
    return matcher.find() ? matcher.group(1) : null;
  }

  private static boolean containGroup(int higGroupId, int[] groupIds) {
    if (higGroupId == -1) {
      return true;
    } else {
      int[] var2 = groupIds;
      int var3 = groupIds.length;

      for (int var4 = 0; var4 < var3; ++var4) {
        int g = var2[var4];
        if (g == higGroupId) {
          return true;
        }
      }

      return false;
    }
  }

  public static Object getProperty(Object bean, String name, String defaultValue) {
    try {
      Field declaredField = bean.getClass().getDeclaredField(name);
      declaredField.setAccessible(true);
      Object value = declaredField.get(bean);
      return value == null ? defaultValue : value;
    } catch (Exception var5) {
      LogFactory.getLog(Tools.class).error(var5.getMessage(), var5);
      return null;
    }
  }

  public static void staticWhereIn(String propName, String belongParms, Collection<?> objectList, AbstractSQL<?> sql,
      Map params) {
    staticWhereList(propName, "%s in (%s)", belongParms, objectList, sql, params);
  }

  public static void staticWhereNotIn(String propName, String belongParms, Collection<?> objectList, AbstractSQL<?> sql,
      Map params) {
    staticWhereList(propName, "%s not in (%s)", belongParms, objectList, sql, params);
  }

  /**
   * 静态拼接where条件
   *
   * @param propName
   *          属性名称
   * @param op
   *          拼接条件
   * @param belongParms
   *          表别名
   * @param objectList
   * @param sql
   * @param params
   */
  public static void staticWhereList(String propName, String op, String belongParms, Collection<?> objectList,
      AbstractSQL<?> sql, Map<String, Object> params) {
    String colName = toUnderLine(propName);
    List<String> sqlVarKeys = new ArrayList<>();

    int i = 0;
    Iterator<?> var9 = objectList.iterator();
    while (var9.hasNext()) {
      Object var = var9.next();
      var = formatIfDate(var);
      String varName = buildVar(propName, params, "ary_" + i, var);
      sqlVarKeys.add(String.format(" #{%s.%s} ", belongParms, varName));
      ++i;
    }
    sql.WHERE(String.format(op, colName, StringUtils.join(sqlVarKeys, ",")));
  }

  public static <E> void setIdIfNull(E record) {
    try {
      Field id = record.getClass().getDeclaredField("id");
      Object idV = getFieldValue(record, id);
      if (idV == null || "".equals(String.valueOf(idV))) {
        id.set(record, UUID.randomUUID().toString());
      }
    } catch (Exception var3) {
    }

  }

  public static String findToken(String input, String partten) {
    Pattern compile = Pattern.compile(partten);
    Matcher matcher = compile.matcher(input);
    return matcher.find() ? matcher.group(1) : null;
  }
}
